package net.sansi.v3correctserver.config;

import cn.hutool.cache.CacheUtil;
import cn.hutool.cache.impl.TimedCache;
import cn.hutool.captcha.ICaptcha;
import cn.hutool.core.date.DateUnit;
import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.Ticker;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.caffeine.CaffeineCache;
import org.springframework.cache.support.SimpleCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * Created by Fang Jianchao
 * create time : 2023/8/21
 * IDE : IntelliJ IDEA
 */
@Configuration
@EnableCaching
public class CacheConfiguration {

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    private static class CacheSpec {
        private long expireTime;
        private long maxSize;
        private TimeUnit timeUnit;
    }

    // 短时缓存，只缓存很短的时间 缓存 10秒
    public static final String SHORT = "SHORT";
    // 一般时间缓存，缓存1小时
    public static final String NORMAL = "NORMAL";
    // 长时间缓存，缓存1天
    public static final String LONG = "LONG";
    // 永久缓存
    public static final String FOREVER = "FOREVER";

    /**
     * 计时器
     *
     * @return 计时器
     */
    @Bean
    public Ticker ticker() {
        return Ticker.systemTicker();
    }

    /**
     * 自定义缓存
     * 可添加多个缓存，用于应对不同的缓存时间需求
     *
     * @param ticker 计时器
     * @return 缓存管理器
     */
    @Bean
    public CacheManager cacheManager(Ticker ticker) {
        SimpleCacheManager manager = new SimpleCacheManager();
        List<CaffeineCache> caches = new ArrayList<>();

        caches.add(buildCache(SHORT, new CacheSpec(10, 10000, TimeUnit.SECONDS), ticker));
        caches.add(buildCache(NORMAL, new CacheSpec(2, 1000, TimeUnit.HOURS), ticker));
        caches.add(buildCache(LONG, new CacheSpec(1, 10000, TimeUnit.DAYS), ticker));
        caches.add(buildCache(FOREVER, new CacheSpec(3650, 10000, TimeUnit.DAYS), ticker));

        manager.setCaches(caches);
        return manager;
    }

    /**
     * 创建 Caffeine 缓存
     *
     * @param name      缓存名称
     * @param cacheSpec 参数
     * @param ticker    计时器
     * @return Caffeine
     */
    private CaffeineCache buildCache(String name, CacheSpec cacheSpec, Ticker ticker) {
        final Caffeine<Object, Object> caffeineBuilder
                = Caffeine.newBuilder()
                .expireAfterWrite(cacheSpec.getExpireTime(), cacheSpec.timeUnit)
                .maximumSize(cacheSpec.getMaxSize())
                .ticker(ticker);
        return new CaffeineCache(name, caffeineBuilder.build());
    }

    /**
     * 验证码缓存
     * 用于存储验证码，有效期5分钟
     * captcha
     */
    @Bean
    public TimedCache<String, ICaptcha> captchaCache() {
        TimedCache<String, ICaptcha> tokenCache = CacheUtil.newTimedCache(DateUnit.MINUTE.getMillis() * 5);
        tokenCache.schedulePrune(DateUnit.HOUR.getMillis() * 2);
        return tokenCache;
    }

}
